Conversation
489acde to
7ff7b03
Compare
7ff7b03 to
58caf0d
Compare
| fn convert_level_filter(filter: tracing::log::LevelFilter) -> tracing_core::LevelFilter { | ||
| match filter { | ||
| tracing::log::LevelFilter::Off => tracing_core::LevelFilter::OFF, | ||
| tracing::log::LevelFilter::Error => tracing_core::LevelFilter::ERROR, | ||
| tracing::log::LevelFilter::Warn => tracing_core::LevelFilter::WARN, | ||
| tracing::log::LevelFilter::Info => tracing_core::LevelFilter::INFO, | ||
| tracing::log::LevelFilter::Debug => tracing_core::LevelFilter::DEBUG, | ||
| tracing::log::LevelFilter::Trace => tracing_core::LevelFilter::TRACE, | ||
| } |
There was a problem hiding this comment.
Is it possible to tracing_core::LevelFilter everywhere instead of having this? (in entrypoint of hyperlight_guest_bin + whatever the host passes to the guest)?
There was a problem hiding this comment.
I think it is doable, I just wanted to avoid breaking changes.
But I think we'll have breaking changes this release anyway
There was a problem hiding this comment.
It turns out it's more complicated that I had anticipated.
First of all, tracing_core::LevelFIlter cannot be cast to u64 as an entrypoint argument. So, we still need to do some conversions.
Secondly, the logger inside the guest, still needs a log::LevelFilter.
The solution I've used is to have a separate hyperlight_common::log_level::GuestLogFilter that can convert from/to u64 and from/to LevelFilter (both log/tracing ones).
I think this is a short term solution, because I am going to eliminate the logger inside the guest, to only use the tracing approach across the guests logs and traces. That will eliminate the need for log::LevelFilter.
Let me know your opinion on this.
|
@dblnz would you like to get this into the next release (we have it scheduled for next week (Feb 25th) |
58caf0d to
3f6bb07
Compare
Yes, I'm rebasing it to include it in the release |
…arent Signed-off-by: Doru Blânzeanu <dblnz@pm.me>
Signed-off-by: Doru Blânzeanu <dblnz@pm.me>
4fc6b1c to
6e47f8f
Compare
… and logging Signed-off-by: Doru Blânzeanu <dblnz@pm.me>
6e47f8f to
72aaf11
Compare
| let level = | ||
| LevelFilter::from(GuestLogFilter::try_from(level as u64).expect("Invalid log level")); | ||
| let level = LevelFilter::iter().nth(level as usize).unwrap().to_level(); |
There was a problem hiding this comment.
should we remove the second level?
| #[cfg(crashdump)] | ||
| use crate::sandbox::uninitialized::SandboxRuntimeConfig; | ||
|
|
||
| /// Get the logging level filter to pass to the guest entrypoint |
There was a problem hiding this comment.
not sure whether I agree that this should go in this file but it's not a blocker
| [dependencies] | ||
| hyperlight-common = { workspace = true, default-features = false } | ||
| spin = "0.10.0" | ||
| tracing = { version = "0.1.44", default-features = false, features = ["attributes"] } |
There was a problem hiding this comment.
did you mean to include this added feature log? https://docs.rs/tracing/latest/tracing/#emitting-log-records. I thought we wanted to switch to tracing
There was a problem hiding this comment.
Pull request overview
This PR fixes issue #990 by implementing proper filtering of guest tracing spans and events based on the max_log_level parameter. Previously, even though the log level was correctly received by guests, only logs were filtered while tracing spans and events were not.
Changes:
- Introduced a new
GuestLogFilterenum to unify log level conversions betweenlog::LevelFilter,tracing_core::LevelFilter, and u64 values passed across the host-guest boundary - Implemented filtering in the
GuestSubscriber::enabled()method to properly filter tracing spans and events based on the maximum log level - Updated trace span levels from
TracetoInfofor infrastructure calls (halt, dispatch_function, call_guest_function, call_host_function) to ensure they are visible at appropriate log levels and updated test expectations accordingly
Reviewed changes
Copilot reviewed 18 out of 22 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
| src/hyperlight_common/src/log_level.rs | New file introducing GuestLogFilter enum with conversions to/from log::LevelFilter, tracing_core::LevelFilter, and u64 |
| src/hyperlight_common/src/lib.rs | Adds log_level module export |
| src/hyperlight_common/Cargo.toml | Adds tracing-core dependency |
| src/hyperlight_guest_tracing/src/subscriber.rs | Adds max_log_level field and implements filtering in enabled() method |
| src/hyperlight_guest_tracing/src/lib.rs | Updates init_guest_tracing to accept LevelFilter parameter |
| src/hyperlight_guest_tracing/Cargo.toml | Adds "log" feature to tracing dependency for log/tracing interop |
| src/hyperlight_guest_bin/src/lib.rs | Updates to use GuestLogFilter for initialization |
| src/hyperlight_guest_bin/src/guest_logger.rs | Minor parameter rename for clarity |
| src/hyperlight_guest_bin/src/guest_function/call.rs | Updates trace levels from Trace to Info and removes explicit parent span references |
| src/hyperlight_host/src/hypervisor/mod.rs | Removes old get_max_log_level function |
| src/hyperlight_host/src/hypervisor/hyperlight_vm.rs | Adds new get_max_log_level_filter and get_guest_log_filter functions with proper conversions |
| src/hyperlight_host/src/sandbox/uninitialized.rs | Updates imports to use tracing_core::LevelFilter |
| src/hyperlight_host/src/sandbox/trace/context.rs | Updates span levels from trace to info |
| src/hyperlight_host/tests/integration_test.rs | Updates test expectations to account for new info-level trace logs and converts to use tracing_core::LevelFilter |
| src/hyperlight_guest/src/exit.rs | Updates halt span level from Trace to Info |
| src/hyperlight_guest/src/guest_handle/io.rs | Removes explicit parent span reference |
| src/hyperlight_guest/src/guest_handle/host_comm.rs | Adds instrumentation and updates trace levels |
| src/tests/rust_guests/simpleguest/src/main.rs | CRITICAL BUG: Incorrect conversion logic in LogMessage function |
| Cargo.lock files | Updates dependency locks for tracing-core additions |
| let level = | ||
| LevelFilter::from(GuestLogFilter::try_from(level as u64).expect("Invalid log level")); | ||
| let level = LevelFilter::iter().nth(level as usize).unwrap().to_level(); |
There was a problem hiding this comment.
The conversion logic on lines 466-468 is incorrect. Line 466-467 converts the input level (i32) to a log::LevelFilter, but then line 468 attempts to use that LevelFilter as a usize index with .nth(level as usize), which is a type error since LevelFilter is an enum that cannot be directly cast to usize.
The correct approach is to call .to_level() directly on the LevelFilter obtained from line 467, without the intermediate .iter().nth() step. The corrected code should be:
let filter = LevelFilter::from(GuestLogFilter::try_from(level as u64).expect("Invalid log level"));
let level = filter.to_level();| let level = | |
| LevelFilter::from(GuestLogFilter::try_from(level as u64).expect("Invalid log level")); | |
| let level = LevelFilter::iter().nth(level as usize).unwrap().to_level(); | |
| let filter = | |
| LevelFilter::from(GuestLogFilter::try_from(level as u64).expect("Invalid log level")); | |
| let level = filter.to_level(); |
| GuestLogFilter::Trace => 5, | ||
| } | ||
| } | ||
| } |
There was a problem hiding this comment.
Consider adding unit tests for the GuestLogFilter conversions to ensure bidirectional conversion correctness between u64, GuestLogFilter, log::LevelFilter, and tracing_core::LevelFilter. This would help prevent regressions if the underlying crate enums change their discriminant values.
| } | |
| } | |
| #[cfg(test)] | |
| mod tests { | |
| use super::GuestLogFilter; | |
| #[test] | |
| fn guest_log_filter_u64_roundtrip() { | |
| let variants = [ | |
| GuestLogFilter::Off, | |
| GuestLogFilter::Error, | |
| GuestLogFilter::Warn, | |
| GuestLogFilter::Info, | |
| GuestLogFilter::Debug, | |
| GuestLogFilter::Trace, | |
| ]; | |
| for variant in variants { | |
| let as_u64: u64 = variant.into(); | |
| let back = GuestLogFilter::try_from(as_u64).expect("conversion from u64 should succeed"); | |
| assert_eq!(variant, back); | |
| } | |
| } | |
| #[test] | |
| fn guest_log_filter_tracing_roundtrip() { | |
| let variants = [ | |
| GuestLogFilter::Off, | |
| GuestLogFilter::Error, | |
| GuestLogFilter::Warn, | |
| GuestLogFilter::Info, | |
| GuestLogFilter::Debug, | |
| GuestLogFilter::Trace, | |
| ]; | |
| for variant in variants { | |
| let tracing_filter: tracing_core::LevelFilter = variant.into(); | |
| let back: GuestLogFilter = tracing_filter.into(); | |
| assert_eq!(variant, back); | |
| } | |
| } | |
| #[test] | |
| fn guest_log_filter_try_from_u64_rejects_invalid() { | |
| // Any value outside the defined range [0, 5] should be rejected. | |
| assert!(GuestLogFilter::try_from(u64::MAX).is_err()); | |
| assert!(GuestLogFilter::try_from(6).is_err()); | |
| } | |
| } |
This closes #990.
Currently, when tracing guests, the max log level parameter provided to the guest is not used to filter out traces.
This PR adds the filtering capability for the guest tracing and also modifies some of the trace levels in the guest.
For that to work, a change in the
integration_tests.rswas necessary to update the number of expected logs inlog_messagetest